package com.ship.dispatch.bpm.utils;

import com.ship.dispatch.bpm.vo.dto.TaskDto;
import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.Process;
import java.util.*;
import java.util.stream.Collectors;

/**
 *@title BpmTaskUtil
 *@description
 *@author yl
 *@create 2023/12/14 0014
 */

public class BpmTaskUtil {
    /**
     * 获取所有用户任务节点
     *
     * @param model bpmnModel对象
     * @return 用户任务节点列表
     */
    public static List<TaskDto> getAllUserTaskEvent(BpmnModel model) {
        Process process = model.getMainProcess();
        Collection<FlowElement> flowElements = process.getFlowElements();
        return getAllUserTaskEvent(flowElements);
    }

    public static String getOutSequenceFlowId(List<SequenceFlow> list){
        StringBuilder resultBuilder = new StringBuilder();
        for (SequenceFlow sequenceFlow : list) {
            resultBuilder.append(sequenceFlow.getId()).append(", ");
        }
        String result = resultBuilder.toString();
        if (result.endsWith(", ")) {
            result = resultBuilder.substring(0, result.length() - 2);
        }
        return result;
    }

    /**
     * 获取所有用户任务节点
     * @param flowElements 流程元素集合
     * @return 用户任务节点列表
     */
    public static  List<TaskDto> getAllUserTaskEvent(Collection<FlowElement> flowElements) {
        List<TaskDto> task = new ArrayList<>();
        Map<String,TaskDto> map = new HashMap<>();
        for (FlowElement flowElement : flowElements) {
            if(flowElement instanceof StartEvent){
                TaskDto dto2 = new TaskDto();
                List<SequenceFlow> list =  ((StartEvent) flowElement).getOutgoingFlows();
                if(list!=null && list.size()>0){
                    dto2.setNextNode(getOutSequenceFlowId(list));
                }
                dto2.setId(flowElement.getId());
                dto2.setNodeType("start");
                map.put(dto2.getId(),dto2);
                task.add(dto2);
            }
            else if(flowElement instanceof UserTask){
                UserTask tempTask =(UserTask) flowElement;
                TaskDto dto2 = new TaskDto();
                dto2.setTaskName(tempTask.getName());
                dto2.setKey(tempTask.getCategory());
                dto2.setId(tempTask.getId());
                dto2.setParentNode(flowElement.getId());
                dto2.setNodeType("UserTask");
                List<SequenceFlow> list =  tempTask.getOutgoingFlows();
                if(list!=null && list.size()>0){
                    dto2.setNextNode(getOutSequenceFlowId(list));
                }
                if(tempTask.getCandidateUsers().size()>0){
                    dto2.setAssigneeId(tempTask.getCandidateUsers().get(0));
                }
                dto2.setCandidateUsers(tempTask.getCandidateUsers());
                map.put(dto2.getId(),dto2);
                task.add(dto2);
            } else if(flowElement instanceof SequenceFlow){
                TaskDto dto = new TaskDto();
                dto.setId(flowElement.getId());
                dto.setParentNode(((SequenceFlow) flowElement).getSourceRef());
                dto.setNextNode(((SequenceFlow) flowElement).getTargetRef());
                map.put(dto.getId(),dto);
                task.add(dto);
            } else if(flowElement instanceof ParallelGateway){
                TaskDto dto2 = new TaskDto();
                dto2.setId(flowElement.getId());
                dto2.setParentNode(flowElement.getId());
                dto2.setNodeType("Gateway");
                List<SequenceFlow> list = ((ParallelGateway) flowElement).getOutgoingFlows();
                if(list!=null && list.size()>0){
                    dto2.setNextNode(getOutSequenceFlowId(list));
                }
                //dto2.setNextNode((ParallelGateway)flowElement.geto);
                map.put(dto2.getId(),dto2);
                task.add(dto2);
            }
            /*if(flowElement instanceof SequenceFlow){
                TaskDto dto = new TaskDto();
                dto.setId(flowElement.getId());
                dto.setParentNode(((SequenceFlow) flowElement).getSourceRef());
                dto.setNextNode(((SequenceFlow) flowElement).getTargetRef());
                FlowElement targetElement = ((SequenceFlow) flowElement).getTargetFlowElement();
                if(targetElement instanceof UserTask){
                    UserTask tempTask =(UserTask) targetElement;
                    TaskDto dto2 = new TaskDto();
                    dto2.setTaskName(tempTask.getName());
                    dto2.setKey(tempTask.getCategory());
                    dto2.setId(tempTask.getId());
                    dto2.setParentNode(flowElement.getId());
                    //dto2.setNextNode(((SequenceFlow)targetElement).getTargetRef());
                    dto2.setNodeType("UserTask");
                    map.put(dto2.getId(),dto2);
                    task.add(dto2);
                } else if(targetElement instanceof ParallelGateway){
                    //targetElement.get
                    TaskDto dto2 = new TaskDto();
                    dto2.setId(targetElement.getId());
                    dto2.setParentNode(flowElement.getId());
                    dto2.setNodeType("Gateway");
                    List<SequenceFlow> list = ((ParallelGateway) targetElement).getOutgoingFlows();
                    StringBuilder resultBuilder = new StringBuilder();
                    for (SequenceFlow sequenceFlow : list) {
                        resultBuilder.append(sequenceFlow.getId()).append(", ");
                    }
                    dto2.setNextNode(resultBuilder.toString());
                    list = ((ParallelGateway) targetElement).getIncomingFlows();
                    resultBuilder = new StringBuilder();
                    for (SequenceFlow sequenceFlow : list) {
                        resultBuilder.append(sequenceFlow.getId()).append(", ");
                    }
                    dto2.setParentNode(resultBuilder.toString());
                    map.put(dto2.getId(),dto2);
                    task.add(dto2);
                }
                if(flowElement instanceof Gateway){
                    dto.setNodeType("Gateway");
                }else {

                }
                task.add(dto);
                map.put(dto.getId(),dto);
            }*/
        }
        System.out.println(JsonUtils.objectToJson(task));
        List<TaskDto> temps = new ArrayList<>();
        List<String> startKeys = new ArrayList<>();
        for(TaskDto dto:task){
            if(dto.getNodeType()!=null && dto.getNodeType() == "UserTask"){
                TaskDto parnentNode = map.get(dto.getParentNode());
                if(parnentNode !=null && "startEvent1".equals(parnentNode.getParentNode())){
                    dto.setParentNode("startEvent1");
                    dto.setFirstFlag(1);
                }
                List<String> keys = new ArrayList<>();
                if(dto.getNextNode()!=null){
                    nextTaskId(keys,flowElements,dto.getNextNode(),map);
                }
                if(keys.size()>0){
                    dto.setNextNode(keys.stream().map(String::valueOf).collect(Collectors.joining(",")));
                }else {
                    dto.setFirstFlag(-1);
                    dto.setNextNode(null);
                }
                temps.add(dto);
            }
            if(dto.getNodeType()=="start"){
                nextTaskId(startKeys,flowElements,dto.getNextNode(),map);
            }
        }
        if(startKeys.size()>0){
            for (String key:startKeys){
                for(TaskDto dto:temps){
                    if(key == dto.getId()){
                        dto.setFirstFlag(1);
                    }
                }
            }
        }
        return temps;
    }

    public static void nextTaskId(List<String> keys,Collection<FlowElement> flowElements, String id, Map<String,TaskDto> map){
        for(FlowElement dto : flowElements){
            if(id.contains(dto.getId())){
                if(dto instanceof UserTask){
                    System.out.println(dto.getId());
                    keys.add(dto.getId());
                }else {
                    TaskDto taskDto = map.get(dto.getId());
                    if(taskDto!=null && taskDto.getNextNode()!=null){
                       nextTaskId(keys,flowElements,taskDto.getNextNode(),map);
                    }
                }
            }
           /* if(dto.getParentNode().contains(id)){
                if("UserTask".equals(dto.getNodeType())){
                    nextId +=  dto.getId() +",";
                }else {
                    nextId = nextTaskId(list,dto.getId());
                }
            }*/
        }
    }
}
